package org.hzero.data.permission.plugins.helper;

import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Invocation;
import org.hzero.data.permission.annotations.PermissionControl;
import org.hzero.data.permission.builder.DataPermissionBuilder;
import org.hzero.data.permission.builder.impl.DefaultDataPermissionBuilder;
import org.hzero.data.permission.constants.DataPermissionSql;
import org.hzero.data.permission.constants.SqlSymbol;
import org.hzero.data.permission.dto.DataPermissionDTO;
import org.hzero.data.permission.dto.HrOrgUnit;
import org.hzero.data.permission.dto.OrderColumnDTO;
import org.hzero.data.permission.dto.UserInfoDTO;
import org.hzero.data.permission.plugins.SimpleSqlSource;
import org.hzero.data.permission.plugins.function.OrgInfoFunction;
import org.hzero.data.permission.plugins.function.UserInfoFunction;
import org.hzero.interfaces.common.utils.KnifeReflectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 实现数据权限的工具类
 *
 * @author tianhao.luo@hand-china.com
 */
public class DataPermissionHelper {
    public static final Logger LOGGER = LoggerFactory.getLogger(DataPermissionHelper.class);
    /**
     * 分页查询的第一步，查询总数的mapperId的后缀
     */
    private static final String COUNT_END = "_COUNT";
    /**
     * 管理员
     */
    private static final String ADMIN = "ADMIN";
    /**
     * 实际分页查询，生成的临时表名
     */
    private static final String TMP_PAGE = "tmp_page";
    /**
     * 缓存
     */
    private static final Map<String, Boolean> CACHE = new ConcurrentHashMap<>(128);

    /**
     * 角色是否管理员缓存
     */
    private static final Map<String, Long> ROLE_CACHE = new ConcurrentHashMap<>(12);
    /**
     * 分页标记的索引位置
     */
    private static final ThreadLocal<Integer> TMP_PAGE_INDEX_THREAD_LOCAL = ThreadLocal.withInitial(() -> -1);

    /**
     * 原生查询
     */
    @Autowired
    private JdbcTemplate jdbcTemplate;


    /**
     * 获取当前执行的mapper方法的命名空间
     *
     * @param mappedStatement 会话
     * @return 命名空间
     */
    private String getNameSpace(MappedStatement mappedStatement) {
        Assert.notNull(mappedStatement, "mybatis会话不能为空");
        return mappedStatement.getId();
    }

    /**
     * 获取当前执行的mapper方法的方法名
     *
     * @param mappedStatement 会话
     * @return 方法名
     */
    private String getMethodName(MappedStatement mappedStatement) {
        String nameSpace = getNameSpace(mappedStatement);
        return nameSpace.substring(nameSpace.lastIndexOf(".") + 1);
    }

    /**
     * 获取当前执行的mapper方法，会替换查询总数的mapperId，获取实际的原始查询方法
     *
     * @param mappedStatement 会话
     * @param methodName      方法名
     * @return 反射获取的方法
     */
    private Method getMethod(MappedStatement mappedStatement, String methodName) {
        Class<?> mapperClass = getClass(mappedStatement);
        if (methodName.endsWith(COUNT_END)) {
            methodName = methodName.replace(COUNT_END, "");
        }
        return KnifeReflectUtil.getMethodNotRecursion(mapperClass, methodName);
    }

    /**
     * 获取mapper命名空间的class
     *
     * @param mappedStatement 会话
     * @return 类class
     */
    private Class<?> getClass(MappedStatement mappedStatement) {
        try {
            String nameSpace = getNameSpace(mappedStatement);
            String className = nameSpace.substring(0, nameSpace.lastIndexOf("."));
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            LOGGER.error("通过mapper命名空间获取class失败:{}", e.getMessage());
            return null;
        }
    }


    /**
     * 获取会话
     *
     * @param invocation 拦截器形参
     * @return 会话
     */
    private MappedStatement getMappedStatement(Invocation invocation) {
        return (MappedStatement) invocation.getArgs()[0];
    }

    /**
     * 获取mapper方法中的参数对象
     *
     * @param invocation 拦截器形参
     * @return 参数
     */
    private Object getParamObj(Invocation invocation) {
        return invocation.getArgs()[1];
    }

    /**
     * 当前登陆用户是admin账号
     *
     * @return 是否为管理员角色
     */
    public Boolean isAdmin() {
        return isOrderRole(ADMIN);
    }


    /**
     * 当前登陆用户是否为admin账号
     *
     * @param userInfoDto 请求
     * @return 是否为管理员角色
     */
    public Boolean isAdmin(UserInfoDTO userInfoDto) {
        return isOrderRole(userInfoDto, ADMIN);
    }

    /**
     * 当前登陆用户是否为admin账号
     *
     * @param currRoleId currRoleId
     * @return 是否为管理员角色
     */
    public Boolean isAdmin(Long currRoleId) {
        return isOrderRole(currRoleId, ADMIN);
    }

    /**
     * 判断登陆用户的角色是否为指定角色编码
     *
     * @param roleCode 角色编码
     * @return 匹配返回true
     */
    public Boolean isOrderRole(String roleCode) {
        UserInfoDTO currThreadUserInfo = UserDetailHelper.getCurrThreadUserInfo();
        return isOrderRole(currThreadUserInfo, roleCode);
    }

    /**
     * 判断登陆用户的角色是否为指定角色编码
     *
     * @param userInfoDto 请求
     * @param roleCode    角色编码
     * @return 匹配返回true
     */
    public Boolean isOrderRole(UserInfoDTO userInfoDto, String roleCode) {
        Long currRoleId = userInfoDto.getRoleId();
        Long adminId = ROLE_CACHE.get(roleCode);
        if (adminId != null) {
            return adminId.equals(currRoleId);
        } else {
            Long roleId = getRoleId(roleCode);
            ROLE_CACHE.put(roleCode, roleId);
            return currRoleId.equals(roleId);
        }
    }

    /**
     * 判断登陆用户的角色是否为指定角色编码
     *
     * @param currRoleId currRoleId
     * @param roleCode   角色编码
     * @return 匹配返回true
     */
    public Boolean isOrderRole(Long currRoleId, String roleCode) {
        Long adminId = ROLE_CACHE.get(roleCode);
        if (adminId != null) {
            return adminId.equals(currRoleId);
        } else {
            Long roleId = getRoleId(roleCode);
            ROLE_CACHE.put(roleCode, roleId);
            return currRoleId.equals(roleId);
        }
    }

    /**
     * 判断是否要进行权限控制
     *
     * @param invocation 拦截器形参
     * @return 参数
     */
    public Boolean isPermissionControl(Invocation invocation) {
        MappedStatement mappedStatement = getMappedStatement(invocation);
        String mapperSqlId = getMapperSqlId(mappedStatement);
        Boolean cacheBoolean = CACHE.get(mapperSqlId);
        // 走缓存
        if (cacheBoolean != null) {
            return cacheBoolean;
        } else {
            Method method = getMethod(mappedStatement, getMethodName(mappedStatement));
            if (method == null) {
                return false;
            }
            PermissionControl annotation = method.getAnnotation(PermissionControl.class);
            CACHE.put(mapperSqlId, annotation != null);
            return annotation != null;
        }
    }

    /**
     * 查询当前登陆用户角色针对mapperSqlId的权限控制记录
     *
     * @param roleId      角色id
     * @param mapperSqlId mapperSqlId
     * @return 权限控制范围记录
     */
    private List<OrderColumnDTO> queryDataPermissionOrderList(Long roleId, String mapperSqlId) {
        Object[] args = {1, roleId, mapperSqlId};
        List<Map<String, Object>> map = jdbcTemplate.queryForList(DataPermissionSql.PERMISSION_SQL, args);
        if (!CollectionUtils.isEmpty(map)) {
            return KnifeReflectUtil.covertListMap(OrderColumnDTO.class, map);
        } else {
            return null;
        }
    }

    /**
     * 获取指定角色编码的角色id
     *
     * @param roleCode 角色编码
     * @return 角色id
     */
    private Long getRoleId(String roleCode) {
        if (StringUtils.isEmpty(roleCode)) {
            return null;
        }
        Object[] args = {roleCode};
        return jdbcTemplate.queryForObject(DataPermissionSql.ROLE_ADMIN_ID, Long.class, args);
    }

    /**
     * 获取employeeCode的所有岗位对应的部门
     *
     * @param employeeCode 员工编码
     * @return 部门
     */
    private List<HrOrgUnit> queryCurrEmployeeUnitList(String employeeCode) {
        Object[] args = {employeeCode};
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(DataPermissionSql.PERSON_UNIT_SQL, args);
        if (CollectionUtils.isEmpty(mapList)) {
            return null;
        } else {
            return KnifeReflectUtil.covertListMap(HrOrgUnit.class, mapList);
        }
    }

    /**
     * 获取角色对应要截取levelpath的长度
     *
     * @param roleId 角色
     * @return levelpath的实际要求长度
     */
    private Integer getLevelPathLength(Long roleId) {
        Object[] args = {roleId};
        String attribute3 = jdbcTemplate.queryForObject(DataPermissionSql.ROLE_ATTRIBUTE3_SQL, String.class, args);
        return StringUtils.isEmpty(attribute3) ? null : Integer.valueOf(attribute3);
    }

    /**
     * 获取会话的mapperSqlId
     *
     * @param mappedStatement 会话
     * @return mapperSqlId
     */
    private String getMapperSqlId(MappedStatement mappedStatement) {
        String mapperSqlId = mappedStatement.getId();
        if (mapperSqlId.endsWith(COUNT_END)) {
            mapperSqlId = mapperSqlId.replace(COUNT_END, "");
        }
        return mapperSqlId;
    }

    /**
     * 手动构造权限对象,不进行替换当前人的组织levelpath字段
     *
     * @param mapperSqlId sqlId
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDto(String mapperSqlId) {
        UserInfoDTO currThreadUserInfo = UserDetailHelper.getCurrThreadUserInfo();
        return getDataPermissionDto(
                new DefaultDataPermissionBuilder(),
                null,
                mapperSqlId,
                currThreadUserInfo);
    }


    /**
     * 手动构造权限对象
     *
     * @param mapperSqlId sqlId
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDtoWithReplaceLevelPath(String mapperSqlId) {
        UserInfoDTO currThreadUserInfo = UserDetailHelper.getCurrThreadUserInfo();
        return getDataPermissionDto(
                new DefaultDataPermissionBuilder(),
                new DefaultLevelPathReplaceFunction(),
                mapperSqlId,
                currThreadUserInfo);
    }




    /**
     * 手动构造权限对象,不进行替换当前人的组织levelpath字段
     *
     * @param mapperSqlId sqlId
     * @param userInfoDto 请求
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDto(String mapperSqlId,
                                                  UserInfoDTO userInfoDto) {
        return getDataPermissionDto(
                new DefaultDataPermissionBuilder(),
                new DefaultLevelPathReplaceFunction(),
                mapperSqlId,
                userInfoDto);
    }


    /**
     * 手动构造权限对象
     *
     * @param mapperSqlId sqlId
     * @param userInfoDto 请求
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDtoWithReplaceLevelPath(String mapperSqlId,
                                                                      UserInfoDTO userInfoDto) {
        return getDataPermissionDto(
                new DefaultDataPermissionBuilder(),
                null,
                mapperSqlId,
                userInfoDto);
    }

    /**
     * 手动构造权限对象
     *
     * @param dataPermissionBuilder    权限对象构造器
     * @param levelPathReplaceFunction 替换levelpath的操作
     * @param mapperSqlId              sqlId
     * @param userInfoDto              请求
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDto(DataPermissionBuilder<HrOrgUnit, UserInfoDTO> dataPermissionBuilder,
                                                  LevelPathReplaceFunction<HrOrgUnit> levelPathReplaceFunction,
                                                  String mapperSqlId,
                                                  UserInfoDTO userInfoDto) {
        return getDataPermissionDto(dataPermissionBuilder,
                levelPathReplaceFunction,
                new DefaultOrgInfoFunction(),
                new DefaultUserInfoFunction(),
                mapperSqlId,
                userInfoDto);
    }

    /**
     * 构造权限
     *
     * @param dataPermissionBuilder    权限对象构造器
     * @param levelPathReplaceFunction levelPath操作
     * @param orgInfoFunction          组织信息操作
     * @param userInfoFunction         用户信息操作
     * @param mapperSqlId              mapperSqlId
     * @param userInfoDto              当前请求的用户信息
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDto(DataPermissionBuilder<HrOrgUnit, UserInfoDTO> dataPermissionBuilder,
                                                  LevelPathReplaceFunction<HrOrgUnit> levelPathReplaceFunction,
                                                  OrgInfoFunction<HrOrgUnit> orgInfoFunction,
                                                  UserInfoFunction<UserInfoDTO> userInfoFunction,
                                                  String mapperSqlId,
                                                  UserInfoDTO userInfoDto) {
        DataPermissionDTO dataPermissionDTO = null;
        Long roleId = userInfoDto.getRoleId();
        // 默认获取启用的数据
        List<OrderColumnDTO> dataPermissionList = queryDataPermissionOrderList(roleId, mapperSqlId);
        if (dataPermissionList != null) {
            String employeeCode = userInfoDto.getEmployeeCode();
            if (employeeCode != null && !"".equals(employeeCode)) {
                List<HrOrgUnit> hrOrgUnits = queryCurrEmployeeUnitList(employeeCode);
                // 处理当前人关联组织的levelPath字段
                if (levelPathReplaceFunction != null) {
                    levelPathReplaceFunction.splitLevelPathByRoleId(hrOrgUnits, getLevelPathLength(roleId), orgInfoFunction);
                }
                dataPermissionDTO = dataPermissionBuilder.buildMultipleTableJoinAndWhereSql(
                        dataPermissionList,
                        hrOrgUnits,
                        orgInfoFunction,
                        userInfoDto,
                        userInfoFunction
                );
            }
        }
        return dataPermissionDTO;
    }


    /**
     * 获取生成的权限对象，不进行替换当前人的组织levelpath字段
     *
     * @param invocation 拦截器形参
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDto(Invocation invocation) {
        return getDataPermissionDto(
                invocation,
                new DefaultDataPermissionBuilder(),
                null
        );
    }

    /**
     * 获取生成的权限对象，使用默认的替换操作
     *
     * @param invocation 拦截器形参
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDtoWithReplaceLevelPath(Invocation invocation) {
        return getDataPermissionDto(
                invocation,
                new DefaultDataPermissionBuilder(),
                new DefaultLevelPathReplaceFunction()
        );
    }


    /**
     * 获取生成的权限对象
     *
     * @param invocation            拦截器形参
     * @param dataPermissionBuilder 权限构造器
     * @return 权限对象
     */
    public DataPermissionDTO getDataPermissionDto(Invocation invocation,
                                                  DataPermissionBuilder<HrOrgUnit, UserInfoDTO> dataPermissionBuilder,
                                                  LevelPathReplaceFunction<HrOrgUnit> levelPathReplaceFunction) {
        UserInfoDTO currThreadUserInfo = UserDetailHelper.getCurrThreadUserInfo();
        MappedStatement mappedStatement = getMappedStatement(invocation);
        String mapperSqlId = getMapperSqlId(mappedStatement);
        return getDataPermissionDto(dataPermissionBuilder, levelPathReplaceFunction, mapperSqlId, currThreadUserInfo);
    }

    /**
     * 获取当前会话绑定的sql
     *
     * @param mappedStatement 会话
     * @param paramObj        mapper方法参数
     * @return 绑定的sql
     */
    private BoundSql getBoundSql(MappedStatement mappedStatement, Object paramObj) {
        return mappedStatement.getBoundSql(paramObj);
    }

    /**
     * 替换当前会话绑定的sql
     *
     * @param invocation        拦截器形参
     * @param dataPermissionDto 数据权限对象
     */
    public void replaceBoundSql(Invocation invocation, DataPermissionDTO dataPermissionDto) {
        MappedStatement mappedStatement = getMappedStatement(invocation);
        Object paramObj = getParamObj(invocation);
        replaceBoundSql(invocation, mappedStatement, paramObj, dataPermissionDto);
    }


    /**
     * 替换当前会话绑定的sql
     *
     * @param invocation        拦截器形参
     * @param mappedStatement   会话
     * @param paramObj          mapper方法参数
     * @param dataPermissionDto 数据权限对象
     */
    private void replaceBoundSql(Invocation invocation, MappedStatement mappedStatement, Object paramObj, DataPermissionDTO dataPermissionDto) {
        BoundSql boundSql = getBoundSql(mappedStatement, paramObj);
        String oldSql = boundSql.getSql();
        LOGGER.debug("原始sql:{}", oldSql);
        String newSql = analysisSql(oldSql, dataPermissionDto);
        LOGGER.debug("权限sql:{}", newSql);
        MappedStatement tempMappedStatement = newMappedStatement(mappedStatement, newSql, boundSql);
        invocation.getArgs()[0] = tempMappedStatement;
    }

    /**
     * 生成新的会话
     *
     * @param ms                 会话
     * @param permissionBoundSql 具有权限控制sql
     * @param boundSql           原始绑定的sql
     * @return 新会话
     */
    private MappedStatement newMappedStatement(MappedStatement ms, String permissionBoundSql, BoundSql boundSql) {
        SimpleSqlSource simpleSqlSource = new SimpleSqlSource(permissionBoundSql, ms.getConfiguration(), boundSql);
        // 新建一个用于映射查询类型sql返回查询结果总数的MappedStatement
        MappedStatement.Builder builder = new MappedStatement.Builder(
                ms.getConfiguration(),
                ms.getId() + "_PERMISSION",
                simpleSqlSource,
                ms.getSqlCommandType()
        );
        // 传递一些默认属性
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());

        if (ms.getKeyProperties() != null &&
                ms.getKeyProperties().length != 0) {
            StringBuilder keyProperties = new StringBuilder();
            for (String keyProperty : ms.getKeyProperties()) {
                keyProperties.append(keyProperty).append(",");
            }
            keyProperties.delete(
                    keyProperties.length() - 1, keyProperties.length()
            );
            builder.keyProperty(keyProperties.toString());
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(ms.getResultMaps());
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }

    /**
     * 解析原始sql，并构造出权限控制sql
     * <p>
     * 需要实现的效果：
     * 1 在from的表的最后添加上我们的权限连接语句
     * 2 在where的后面添加and 和我们的过滤语句
     * 3 如果没有where，我们需要手动构造一个where，并添加我们的过滤语句
     *
     * @param oldSql            原始sql
     * @param dataPermissionDto 权限对象
     * @return 具有权限控制的sql
     */
    private String analysisSql(String oldSql, DataPermissionDTO dataPermissionDto) {
        try {
            List<String> sqlWordList = analysisSql(oldSql);
            // 找出现TMP_PAGE的索引
            int i = sqlWordList.size() - 1, tempPageIndex = TMP_PAGE_INDEX_THREAD_LOCAL.get();
            boolean lastFirstWhereExistFlag = true;
            while (i >= 0) {
                // 找到倒数第一个where,注意where不要有换行符或者严格使用<where>标签
                if ((SqlSymbol.WHERE.equalsIgnoreCase(sqlWordList.get(i))
                        || (SqlSymbol.WHERE + SqlSymbol.WRAP).equalsIgnoreCase(sqlWordList.get(i)))
                        && (tempPageIndex == -1 || i < tempPageIndex)) {
                    lastFirstWhereExistFlag = false;
                    break;
                }
                i--;
            }
            // 补充sql语句
            if (lastFirstWhereExistFlag) {
                // 语句中没有where，则手动构造
                sqlWordList.add(dataPermissionDto.getLeftJoinSql() + SqlSymbol.SPACE + SqlSymbol.WHERE + SqlSymbol.SPACE + dataPermissionDto.getWhereSql());
            } else {
                // 在where前面插入left join语句。在where后插入条件语句
                sqlWordList.add(i, dataPermissionDto.getLeftJoinSql());
                sqlWordList.add(i + 2, dataPermissionDto.getWhereSql() + SqlSymbol.SPACE + SqlSymbol.AND);
            }
            return String.join(SqlSymbol.SPACE, sqlWordList);
        } finally {
            TMP_PAGE_INDEX_THREAD_LOCAL.remove();
        }
    }

    /**
     * 以空格为分界符，将sql解析为单词集合
     *
     * @param oldSql 原始sql
     * @return 单词集合
     */
    private List<String> analysisSql(String oldSql) {
        oldSql = oldSql.replace("\t", " ");
        int length = oldSql.length(), slow = 0, fast = slow + 1, index = 0;
        List<String> wordList = new LinkedList<>();
        while (slow < length && fast < length) {
            char slowChar = oldSql.charAt(slow);
            // 找到第一个有值的位置
            while (slowChar == ' ' && slow + 1 < length) {
                slow++;
                slowChar = oldSql.charAt(slow);
            }
            // 找到第一个结束的位置
            fast = slow;
            char fastChar = oldSql.charAt(fast);
            while (fastChar != ' ') {
                fast++;
                if (fast < length) {
                    fastChar = oldSql.charAt(fast);
                } else {
                    break;
                }
            }
            if (slow != fast) {
                String tempWord = oldSql.substring(slow, fast);
                wordList.add(tempWord);
                // 补充是否是分页查询的sql
                if (TMP_PAGE.equalsIgnoreCase(tempWord) || (TMP_PAGE + SqlSymbol.WRAP).equals(tempWord)
                        || "table_count".equalsIgnoreCase(tempWord) || "table_count\n".equalsIgnoreCase(tempWord)) {
                    TMP_PAGE_INDEX_THREAD_LOCAL.set(index);
                }
            } else {
                wordList.add(oldSql.substring(slow));
            }
            // 移动slow
            fast++;
            slow = fast;
            // list计数器
            index++;
        }
        return wordList;
    }


    /**
     * 模糊查询时，不能直接使用组织对应的levelpath，而是需要截取levelpath时，可实现该方法
     *
     * @param <T> 范型，占位符
     */
    interface LevelPathReplaceFunction<T> {

        /**
         * 根据当前用户的角色，来对当前用户关联的组织的levelPath进行截取操作
         * <p>
         * 原因是：A组织下属有B组织，现在A组织的领导并未挂在A组织上，而是挂在和B组织平级的一个领导岗位上。
         * 通过levelpath做权限匹配时，需要把领导的levelPath向上截取
         *
         * @param hrOrgUnits      人员关联的组织
         * @param length          需要截取levelPath的长度
         * @param orgInfoFunction 处理levelPath的方式
         */
        void splitLevelPathByRoleId(List<T> hrOrgUnits, Integer length, OrgInfoFunction<T> orgInfoFunction);
    }

    /**
     * 默认的替换levelpath的操作
     * <p>
     * #1 需要引入本项目下的组织信息实体类，替换HrOrgUnit
     */
    public static class DefaultLevelPathReplaceFunction implements LevelPathReplaceFunction<HrOrgUnit> {

        @Override
        public void splitLevelPathByRoleId(List<HrOrgUnit> hrOrgUnits, Integer length, OrgInfoFunction<HrOrgUnit> orgInfoFunction) {
            // 不做处理
            if (length == null) {
                return;
            }
            // 替换
            for (HrOrgUnit hrOrgUnit : hrOrgUnits) {
                String levelPath = orgInfoFunction.getLevelPath(hrOrgUnit);
                if (!StringUtils.isEmpty(levelPath) && levelPath.length() >= length) {
                    // 截取
                    String parentOrgLevelPath = levelPath.substring(0, length);
                    orgInfoFunction.setLevelPath(hrOrgUnit, parentOrgLevelPath);
                }
            }
        }
    }

    /**
     * 默认的获取/回写levelpath的操作
     * <p>
     * #1 需要引入本项目下的组织信息实体类，替换HrOrgUnit
     * #2 提供获取levelPath和设置levelPath的方法，等
     */
    static class DefaultOrgInfoFunction implements OrgInfoFunction<HrOrgUnit> {

        @Override
        public String getLevelPath(HrOrgUnit hrOrgUnit) {
            return hrOrgUnit.getAttribute4();
        }

        @Override
        public void setLevelPath(HrOrgUnit hrOrgUnit, String levelPath) {
            hrOrgUnit.setAttribute4(levelPath);
        }

        @Override
        public Long getUnitId(HrOrgUnit hrOrgUnit) {
            return hrOrgUnit.getUnitId();
        }
    }

    /**
     * 默认的获取用户信息的操作
     */
    static class DefaultUserInfoFunction implements UserInfoFunction<UserInfoDTO> {

        @Override
        public String getEmployeeCode(UserInfoDTO userInfoDTO) {
            return userInfoDTO.getEmployeeCode();
        }

        @Override
        public Long getUserId(UserInfoDTO userInfoDTO) {
            return userInfoDTO.getUserId();
        }

        @Override
        public Long getRoleId(UserInfoDTO userInfoDTO) {
            return userInfoDTO.getRoleId();
        }
    }
}
